home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
3D Images
/
3D Images.iso
/
programs
/
amiga
/
rayshade
/
inetray
/
irtrace.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-01-12
|
12KB
|
477 lines
/*======================================================================
I R T R A C E . C
doc: Tue Mar 3 10:50:23 1992
dlm: Sun Jul 5 15:41:44 1992
(c) 1992 ant@julia
uE-Info: 154 74 T 0 0 72 2 2 8 ofnI
======================================================================*/
/*#define FULL_SAMPLING*/
#include "rayshade.h"
#include "libsurf/atmosphere.h"
#include "libsurf/surface.h"
#include "libcommon/sampling.h"
#include "options.h"
#include "stats.h"
#include "viewing.h"
#include "picture.h"
#include "irtrace.h"
#define UNSAMPLED -1
#define SUPERSAMPLED -2
static void FullySamplePixel(); /* private routines */
static void AdaptiveRefineScanline();
static void FullySampleScanline();
static void SingleSampleScanline();
static int ExcessiveContrast();
static Float SampleTime();
static Ray TopRay; /* Top-level ray. */
static int *SampleNumbers;
static Scanline *scan;
/*
* "Dither matrices" used to encode the 'number' of a ray that samples a
* particular portion of a pixel. Hand-coding is ugly, but...
*/
static int OneSample[1] = {0};
static int TwoSamples[4] = {0, 2,
3, 1};
static int ThreeSamples[9] = {0, 2, 7,
6, 5, 1,
3, 8, 4};
static int FourSamples[16] = { 0, 8, 2, 10,
12, 4, 14, 6,
3, 11, 1, 9,
15, 7, 13, 5};
static int FiveSamples[25] = { 0, 8, 23, 17, 2,
19, 12, 4, 20, 15,
3, 21, 16, 9, 6,
14, 10, 24, 1, 13,
22, 7, 18, 11, 5};
static int SixSamples[36] = { 6, 32, 3, 34, 35, 1,
7, 11, 27, 28, 8, 30,
24, 14, 16, 15, 23, 19,
13, 20, 22, 21, 17, 18,
25, 29, 10, 9, 26, 12,
36, 5, 33, 4, 2, 31};
static int SevenSamples[49] = {22, 47, 16, 41, 10, 35, 4,
5, 23, 48, 17, 42, 11, 29,
30, 6, 24, 49, 18, 36, 12,
13, 31, 7, 25, 43, 19, 37,
38, 14, 32, 1, 26, 44, 20,
21, 39, 8, 33, 2, 27, 45,
46, 15, 40, 9, 34, 3, 28};
static int EightSamples[64] = { 8, 58, 59, 5, 4, 62, 63, 1,
49, 15, 14, 52, 53, 11, 10, 56,
41, 23, 22, 44, 45, 19, 18, 48,
32, 34, 35, 29, 28, 38, 39, 25,
40, 26, 27, 37, 36, 30, 31, 33,
17, 47, 46, 20, 21, 43, 42, 24,
9, 55, 54, 12, 13, 51, 50, 16,
64, 2, 3, 61, 60, 6, 7, 57};
RaytraceInit(argc, argv)
int argc;
char **argv;
{
RSInitialize(argc,argv);
switch (Sampling.sidesamples) {
case 1:
SampleNumbers = OneSample;
break;
case 2:
SampleNumbers = TwoSamples;
break;
case 3:
SampleNumbers = ThreeSamples;
break;
case 4:
SampleNumbers = FourSamples;
break;
case 5:
SampleNumbers = FiveSamples;
break;
case 6:
SampleNumbers = SixSamples;
break;
case 7:
SampleNumbers = SevenSamples;
break;
case 8:
SampleNumbers = EightSamples;
break;
default:
RLerror(RL_PANIC,
"Sorry, %d rays/pixel not supported.\n",
Sampling.totsamples);
}
return Screen.xsize;
}
Scanline *Raytrace(bSz,lNr)
int bSz,lNr;
{
int x,y,i;
/* ----------- */
/* alloc stuff */
/* ----------- */
scan = (Scanline *)Malloc((bSz+2)*sizeof(Scanline));
if (scan == NULL) {
fprintf(stderr,"Malloc() failed\n");
exit(1);
}
for (y=0; y<bSz+2; y++) {
scan[y].pix = (Pixel *)Malloc(Screen.xsize * sizeof(Pixel));
if (scan[y].pix == NULL) {
fprintf(stderr,"Malloc() failed\n");
exit(1);
}
scan[y].samp = (int *)Malloc(Screen.xsize * sizeof(int));
if (scan[y].samp == NULL) {
fprintf(stderr,"Malloc() failed\n");
exit(1);
}
}
/* ------- */
/* Top Ray */
/* ------- */
TopRay.pos = Camera.pos;
TopRay.media = (Medium *)0;
TopRay.depth = 0;
/* ----------- */
/* Trace Block */
/* ----------- */
#ifdef FULL_SAMPLING
for (y=0; y<bSz; y++)
FullySampleScanline(y+lNr,&scan[y+1]);
#else
if (bSz == 1) { /* special case */
FullySampleScanline(lNr,&scan[1]);
return scan;
}
x = Screen.xsize-1;
SingleSampleScanline(lNr+1,&scan[2]);
FullySamplePixel(0, lNr+1, &scan[2].pix[0],
&scan[2].samp[0]);
FullySamplePixel(x, lNr+1, &scan[2].pix[x],
&scan[2].samp[x]);
if (lNr == 0) { /* first block */
FullySampleScanline(0,&scan[1]);
} else { /* 2nd to last */
SingleSampleScanline(lNr-1,&scan[0]);
FullySamplePixel(0, lNr-1, &scan[0].pix[0],
&scan[0].samp[0]);
FullySamplePixel(x, lNr-1, &scan[0].pix[x],
&scan[0].samp[x]);
SingleSampleScanline(lNr,&scan[1]);
FullySamplePixel(0, lNr, &scan[1].pix[0],
&scan[1].samp[0]);
FullySamplePixel(x, lNr, &scan[1].pix[x],
&scan[1].samp[x]);
if (Sampling.sidesamples > 1)
AdaptiveRefineScanline(lNr,
&scan[0],
&scan[1],
&scan[2]);
}
for (y=lNr+1,i=3; i<bSz; y++,i++) { /* main part */
SingleSampleScanline(y+1,&scan[i]);
FullySamplePixel(0, y+1, &scan[i].pix[0],
&scan[i].samp[0]);
FullySamplePixel(x, y+1, &scan[i].pix[x],
&scan[i].samp[x]);
if (Sampling.sidesamples > 1)
AdaptiveRefineScanline(y,
&scan[i-2],
&scan[i-1],
&scan[i]);
}
if (lNr+bSz == Screen.ysize) { /* last block */
FullySampleScanline(lNr+bSz-1,&scan[bSz]);
if (Sampling.sidesamples > 1)
AdaptiveRefineScanline(lNr+bSz-1,
&scan[bSz-2],
&scan[bSz-1],
&scan[bSz]);
} else { /* 1st - 2nd to last */
y = lNr+bSz-1;
SingleSampleScanline(y,&scan[bSz]);
FullySamplePixel(0, y, &scan[bSz].pix[0],
&scan[bSz].samp[0]);
FullySamplePixel(x, y, &scan[bSz].pix[x],
&scan[bSz].samp[x]);
if (Sampling.sidesamples > 1)
AdaptiveRefineScanline(y-1,
&scan[bSz-2],
&scan[bSz-1],
&scan[bSz]);
y = lNr+bSz;
SingleSampleScanline(y,&scan[bSz+1]);
FullySamplePixel(0, y, &scan[bSz+1].pix[0],
&scan[bSz+1].samp[0]);
FullySamplePixel(x, y, &scan[bSz+1].pix[x],
&scan[bSz+1].samp[x]);
if (Sampling.sidesamples > 1)
AdaptiveRefineScanline(y-1,
&scan[bSz-1],
&scan[bSz],
&scan[bSz+1]);
}
#endif
return scan;
}
static void
SingleSampleScanline(line, data)
int line;
Scanline *data;
{
Float upos, vpos, yp;
int x, usamp, vsamp;
Pixel tmp;
yp = line + Screen.miny - 0.5*Sampling.filterwidth;
for (x = 0; x < Screen.xsize; x++) {
/*
* Pick a sample number...
*/
data->samp[x] = nrand() * Sampling.totsamples;
/*
* Take sample corresponding to sample #.
*/
usamp = data->samp[x] % Sampling.sidesamples;
vsamp = data->samp[x] / Sampling.sidesamples;
vpos = yp + vsamp * Sampling.filterdelta;
upos = x + Screen.minx - 0.5*Sampling.filterwidth +
usamp*Sampling.filterdelta;
if (Options.jitter) {
vpos += nrand()*Sampling.filterdelta;
upos += nrand()*Sampling.filterdelta;
}
TopRay.time = SampleTime(SampleNumbers[data->samp[x]]);
SampleScreen(upos, vpos, &TopRay,
&data->pix[x], SampleNumbers[data->samp[x]]);
if (Options.samplemap)
data->pix[x].alpha = 0;
}
}
static void
FullySampleScanline(line, data)
int line;
Scanline *data;
{
int x;
for (x = 0; x < Screen.xsize; x++) {
data->samp[x] = UNSAMPLED;
FullySamplePixel(x, line, &data->pix[x], &data->samp[x]);
}
}
static void
FullySamplePixel(xp, yp, pix, prevsamp)
int xp, yp;
Pixel *pix;
int *prevsamp;
{
Float upos, vpos, u, v;
int x, y, sampnum;
Pixel ctmp;
if (*prevsamp == SUPERSAMPLED)
return; /* already done */
Stats.SuperSampled++;
if (*prevsamp == UNSAMPLED) {
/*
* No previous sample; initialize to black.
*/
pix->r = pix->g = pix->b = pix->alpha = 0.;
} else {
if (Sampling.sidesamples == 1) {
*prevsamp = SUPERSAMPLED;
return;
}
x = *prevsamp % Sampling.sidesamples;
y = *prevsamp / Sampling.sidesamples;
pix->r *= Sampling.filter[x][y];
pix->g *= Sampling.filter[x][y];
pix->b *= Sampling.filter[x][y];
pix->alpha *= Sampling.filter[x][y];
}
sampnum = 0;
xp += Screen.minx;
vpos = Screen.miny + yp - 0.5*Sampling.filterwidth;
for (y = 0; y < Sampling.sidesamples; y++,
vpos += Sampling.filterdelta) {
upos = xp - 0.5*Sampling.filterwidth;
for (x = 0; x < Sampling.sidesamples; x++,
upos += Sampling.filterdelta) {
if (sampnum != *prevsamp) {
if (Options.jitter) {
u = upos + nrand()*Sampling.filterdelta;
v = vpos + nrand()*Sampling.filterdelta;
} else {
u = upos;
v = vpos;
}
TopRay.time = SampleTime(SampleNumbers[sampnum]);
SampleScreen(u, v, &TopRay, &ctmp,
SampleNumbers[sampnum]);
pix->r += ctmp.r*Sampling.filter[x][y];
pix->g += ctmp.g*Sampling.filter[x][y];
pix->b += ctmp.b*Sampling.filter[x][y];
pix->alpha += ctmp.alpha*Sampling.filter[x][y];
}
if (++sampnum == Sampling.totsamples)
sampnum = 0;
}
}
if (Options.samplemap)
pix->alpha = 255;
*prevsamp = SUPERSAMPLED;
}
static void
AdaptiveRefineScanline(y, scan0, scan1, scan2)
int y;
Scanline *scan0, *scan1, *scan2;
{
int x, done;
/*
* Walk down scan1, looking at 4-neighbors for excessive contrast.
* If found, supersample *all* neighbors not already supersampled.
* The process is repeated until either there are no
* high-contrast regions or all such regions are already supersampled.
*/
do {
done = TRUE;
for (x = 1; x < Screen.xsize -1; x++) {
/*
* Find min and max RGB for area we care about
*/
if (ExcessiveContrast(x, scan0->pix, scan1->pix,
scan2->pix)) {
if (scan1->samp[x-1] != SUPERSAMPLED) {
done = FALSE;
FullySamplePixel(x-1, y,
&scan1->pix[x-1],
&scan1->samp[x-1]);
}
if (scan0->samp[x] != SUPERSAMPLED) {
done = FALSE;
FullySamplePixel(x, y-1,
&scan0->pix[x],
&scan0->samp[x]);
}
if (scan1->samp[x+1] != SUPERSAMPLED) {
done = FALSE;
FullySamplePixel(x+1, y,
&scan1->pix[x+1],
&scan1->samp[x+1]);
}
if (scan2->samp[x] != SUPERSAMPLED) {
done = FALSE;
FullySamplePixel(x, y+1,
&scan2->pix[x],
&scan2->samp[x]);
}
if (scan1->samp[x] != SUPERSAMPLED) {
done = FALSE;
FullySamplePixel(x, y,
&scan1->pix[x],
&scan1->samp[x]);
}
}
}
} while (!done);
}
static int
ExcessiveContrast(x, pix0, pix1, pix2)
int x;
Pixel *pix0, *pix1, *pix2;
{
Float mini, maxi, sum, diff;
maxi = max(pix0[x].r, pix1[x-1].r);
if (pix1[x].r > maxi) maxi = pix1[x].r;
if (pix1[x+1].r > maxi) maxi = pix1[x+1].r;
if (pix2[x].r > maxi) maxi = pix2[x].r;
mini = min(pix0[x].r, pix1[x-1].r);
if (pix1[x].r < mini) mini = pix1[x].r;
if (pix1[x+1].r < mini) mini = pix1[x+1].r;
if (pix2[x].r < mini) mini = pix2[x].r;
diff = maxi - mini;
sum = maxi + mini;
if (sum > EPSILON && diff/sum > Options.contrast.r)
return TRUE;
maxi = max(pix0[x].g, pix1[x-1].g);
if (pix1[x].g > maxi) maxi = pix1[x].g;
if (pix1[x+1].g > maxi) maxi = pix1[x+1].g;
if (pix2[x].g > maxi) maxi = pix2[x].g;
mini = min(pix0[x].g, pix1[x-1].g);
if (pix1[x].g < mini) mini = pix1[x].g;
if (pix1[x+1].g < mini) mini = pix1[x+1].g;
if (pix2[x].g < mini) mini = pix2[x].g;
diff = maxi - mini;
sum = maxi + mini;
if (sum > EPSILON && diff/sum > Options.contrast.g)
return TRUE;
maxi = max(pix0[x].b, pix1[x-1].b);
if (pix1[x].b > maxi) maxi = pix1[x].b;
if (pix1[x+1].b > maxi) maxi = pix1[x+1].b;
if (pix2[x].b > maxi) maxi = pix2[x].b;
mini = min(pix0[x].b, pix1[x-1].b);
if (pix1[x].b < mini) mini = pix1[x].b;
if (pix1[x+1].b < mini) mini = pix1[x+1].b;
if (pix2[x].b < mini) mini = pix2[x].b;
diff = maxi - mini;
sum = maxi + mini;
if (sum > EPSILON && diff/sum > Options.contrast.b)
return TRUE;
return FALSE;
}
static Float
SampleTime(sampnum)
int sampnum;
{
Float window, jitter = 0.0, res;
if (Options.shutterspeed <= 0.)
return Options.framestart;
if (Options.jitter)
jitter = nrand();
window = Options.shutterspeed / Sampling.totsamples;
res = Options.framestart + window * (sampnum + jitter);
TimeSet(res);
return res;
}